/*
	Project:	CoreEngine
	Author:		Dino Bojadzhievski
	File:		Transform2Manager

	Defines an abstraction layer over linear transformations in two-dimensional space.

	All performed with homogeneous coordinates (3D vectors and matrices).
	All angles expressed in degrees.
	Positive angles are counter-clockwise.

	Abstracts away the mathematical limitations to performing linear transformations in 2D space.
	Achieves this by translating the vector to the origin, performing transforms, and translating back.
	Allows for transform chaining without manual management of transform order.

	Usage:
	1. Instantiate a Transform2Manager object.
	2. Queue transforms you need executed.
	3. Call Perform on the instance, and assign the final computed value to the vector to be transformed.
*/

#pragma once

#include "../../CoreTypes.h"

#include "../Matrix2.h"
#include "../Matrix3.h"

#include "../Vector3.h"

#include <stack>

#include "../Transform2D.h"

using namespace std;
using namespace CoreMath;

class Transform2Manager
{
private:
	stack<Matrix3> stk_TransformQueue;

public:

	void Init()
	{
			while (!this->stk_TransformQueue.empty())
			this->stk_TransformQueue.pop();
	}

	void QueueScale(const real factorX, const real factorY)
	{
		Matrix3 m_TransformMatrix = GetScalingMatrix(factorX, factorY);
		this->stk_TransformQueue.push(m_TransformMatrix);
	}

	void QueueTranslate(const real dX, const real dY)
	{
		Matrix3 m_TransformMatrix = GetTranslationMatrix(dX, dY);
		this->stk_TransformQueue.push(m_TransformMatrix);
	}

	void QueueRotate(const real angle)
	{
		Matrix3 m_TransformMatrix = GetRotationMatrix(angle);
		this->stk_TransformQueue.push(m_TransformMatrix);
	}

	void QueueShear(const real shearX, const real shearY)
	{
		Matrix3 m_TransformationMatrix = GetShearingMatrix(shearX, shearY);
		this->stk_TransformQueue.push(m_TransformationMatrix);
	}

	void QueueProjection(const Vector2& direction)
	{
		Matrix3 m_TransformationMatrix = GetProjectionMatrix(direction);
		this->stk_TransformQueue.push(m_TransformationMatrix);
	}

	Vector3 Perform(Vector3& vector)
	{
		real i = vector.i;
		real j = vector.j;

		Translate(vector, -i, -j);

		Matrix3 m_TransformMatrix;
		while (!this->stk_TransformQueue.empty())
		{
			m_TransformMatrix *= this->stk_TransformQueue.top();
			this->stk_TransformQueue.pop();
		}

		vector = m_TransformMatrix * vector;
		Translate(vector, i, j);
		return vector;
	}

	void Reset()
	{
		while (!this->stk_TransformQueue.empty())
			this->stk_TransformQueue.pop();
	}
};

